<?php

namespace App\services\v1;

use App\Common\RedisCache\YearActivityCache;
use App\Jobs\activity\YearActivityCommand;
use App\Models\LuckCouponLog;
use App\Models\LuckDrawLog;
use App\services\BaseServices;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Queue;

class LuckServices extends BaseServices
{
    const DESCRIBE = '新年抽奖';
    /**
     * 新年活动抽奖
     * @param int $activityId
     * @return array
     * @throws \Throwable
     */
    public function getLuckLoop(int $activityId): array
    {
        $userId   = $this->user->id;
        $drawTime = date('Y-m-d H:i:s');//抽奖时间
        $startMillisecond   = getMillisecond();
        $laterRedisParamKey = [$userId, $activityId, $startMillisecond];
        $redisParamKey      = [$userId, $activityId];
        //验证用户的抽奖券
        if (!$userDraw = $this->isHaveDraw($userId, $activityId)) {
            $this->resData['code'] = 110100;
            return $this->resData;
        }
        //没获得锁等待
        $yearActivityCache = new YearActivityCache();
        $yearActivityCache->setKeyParameter($redisParamKey);
        if (!$yearActivityCache->set($startMillisecond,['nx','ex' => $yearActivityCache->expire])) {
            $this->resData['code'] = 110101;
            return $this->resData;
        }
        //锁续命
        $yearActivityCache->setKeyParameter($laterRedisParamKey);
        $yearActivityCache->set($startMillisecond, 60);
        $yearActivityCache->setKeyParameter($redisParamKey);
        Queue::later($yearActivityCache->expire-2
            , new YearActivityCommand(['redisKey' => $redisParamKey,'redisValue' => $startMillisecond, 'laterRedisKey' => $laterRedisParamKey, 'describe' => self::DESCRIBE])
            ,''
            ,YearActivityCommand::QUEUE_NAME
        );
        //概率抽奖
        $drawInfo = $this->luckDraw($activityId);
        if (!empty($drawInfo)) {
            try {
                //处理业务逻辑
                DB::transaction(function () use ($userDraw, $userId, $activityId, $drawTime, $drawInfo) {
                    //减券
                    $reduceDrawData = [
                        'number' => $userDraw->number - 1,
                    ];
                    $userDraw->update($reduceDrawData);
                    //加抽奖记录
                    $drawLogData = [
                        'luck_id'   => $userDraw->luck_id,//券ID
                        'user_id'   => $userId,
                        'draw_id'   => $drawInfo['id'],//奖品ID
                        'luck_name' => $userDraw->luck_name,//券名
                        'draw_name' => $drawInfo['name'],//奖品名
                        'user_name' => $this->user->user_name,
                        'draw_time' => $drawTime
                    ];
                    LuckDrawLog::query()->create($drawLogData);
                },2);
            }catch (Exception $exception){
                Log::error(self::DESCRIBE . 'error:', $exception->getTrace());
            } finally {
                //释放锁
                $yearActivityCache->del();
                //释放续命锁
                $yearActivityCache->setKeyParameter($laterRedisParamKey);
                $yearActivityCache->del();
                Log::info(self::DESCRIBE.'finally');
            }
        }

        $this->resData['data'] = $drawInfo;
        return $this->resData;
    }

    public function isHaveDraw(int $userId, int $activityId)
    {
        return LuckCouponLog::query()->whereUserId($userId)->whereActivityId($activityId)
            ->where('number','>',0)->first();
    }

    /**
     * 概率抽奖
     * @param int $activityId
     * @return mixed
     */
    public function luckDraw(int $activityId)
    {
//        sleep(10);//模拟业务超时场景
        $winDrawInfo = [];
        //当期活动的奖品列表
        $drawServices        = new DrawServices();
        //防止奖品数超过10个
        $drawServices->limit = 100;
        $activityDrawList    = $drawServices->getDrawList($activityId)['data'];
        if (!empty($activityDrawList)) {
            //总概率
            $probabilitySum = array_sum(array_column($activityDrawList,'probability'));
            foreach ($activityDrawList as $draw) {
                //中奖的奖品
                if (rand(1, $probabilitySum) <= $draw['probability']) {
                    $winDrawInfo = $draw;
                    break;
                }
                //没中奖 继续循环并减掉抽过的奖品概率
                $probabilitySum = $probabilitySum - $draw['probability'];
            }
        }
        return $winDrawInfo;
    }

    /**
     * 获取抽奖记录
     * @param int $userId
     * @return array
     */
    public function getLuckLog(int $userId = 0): array
    {
        $field = ['id','luck_name','user_name','draw_name','draw_time'];
        $luckLogList = LuckDrawLog::query()
            ->when($userId, function ($q) use($userId) {
                /** @var $q LuckDrawLog */
                $q->whereUserId($userId);
            })
            ->orderBy('id','desc')
            ->paginate($this->limit, $field, 'page', $this->page)->toArray();
        $this->resData['data']  = $luckLogList['data'];
        $this->resData['count'] = $luckLogList['total'];
        return $this->resData;
    }

}